Wang Haihua
🍈 🍉🍊 🍋 🍌
移动平均法是常用的时间序列预测方法, 由于其简单而具有很好的实用价值。
设观测序列为 $y_{1}, \cdots, y_{T}$, 取移动平均的项数 $N<T$ 。一次移动平均值计算公式为 $$M_{t}^{(1)}(N)=\frac{1}{N}\left(y_{t}+y_{t-1}+\cdots+y_{t-N+1}\right)=\frac{1}{N} \sum_{i=0}^{N-1} y_{t-i}$$ 则有 $$M_{t}^{(1)}(N)=\frac{1}{N}\left(y_{t-1}+\cdots+y_{t-N}\right)+\frac{1}{N}\left(y_{t}-y_{t-N}\right)=M_{t-1}^{(1)}(N)+\frac{1}{N}\left(y_{t}-y_{t-N}\right)$$
$t+1$ 期的预测值为 $\hat{y}_{t+1}=M_{t}^{(1)}(N)$, 其预测标准误差为 $$ S=\sqrt{\frac{\sum_{t=N+1}^{T}\left(\hat{y}_{t}-y_{t}\right)^{2}}{T-N}} . $$ 如果将 $\hat{y}_{t+1}$ 作为 $t+1$ 期的实际值, 那么就可以用 $\hat{y}_{t+1}=M_{t}^{(1)}(N)$ 计算第 $t+2$ 期预测值 $\hat{y}_{t+2}$ 。一般地, 也可相应地求得以后各期的预测值。但由于越 远时期的预测, 误差越大,因此一次移动平均法一般仅应用于一个时期后的 预测值(即预测第 $t+1$ 期)。
汽车配件销售某年 1 12 月份的化油器销售量 (单位:只) 统 计数据见表18.1 中第 2 行, 试用一次移动平均法预测下一年 1 月的销售量。
月份 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 预测 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
y_(i) | 423 | 358 | 434 | 445 | 527 | 429 | 426 | 502 | 480 | 384 | 427 | 446 | |
N=3 | 405 | 412 | 469 | 467 | 461 | 452 | 469 | 455 | 430 | 419 | |||
N=5 | 437 | 439 | 452 | 466 | 473 | 444 | 444 | 448 |
分别取 $N=3, N=5$, 按预测公式 $$ \begin{aligned} &\hat{y}_{t+1}(3)=M_{t}^{1}(3)=\frac{y_{t}+y_{t-1}+y_{t-2}}{3}, \quad t=3,4, \cdots, 12, \\ &\hat{y}_{t+1}(5)=M_{t}^{1}(5)=\frac{y_{t}+y_{t-1}+y_{t-2}+y_{t-3}+y_{t-4}}{5}, \quad t=5,6, \cdots, 12, \end{aligned} $$
计算 3 个月和 5 个月移动平均预测值, 分别见表 $18.1$ 第 3 行和第 4 行。 $N=3$ 时, 预测的标准误差为 $56.5752, N=5$ 时, 预测的标准误差为 $39.8159$ 。
通过表可以看到, 实际数据波动较大, 经移动平均后, 随机波动明显减少, 且 $N$ 越大, 波动也越小。同时, 也可以看到, 一次移动平均法的预测标准误差还是有些大, 对于实际数据波动较大的序列, 一般较少采用此法进行预测。
代码
import numpy as np
y=np.array([423,358,434,445,527,429,426,502,480,384,427,446])
def MoveAverage(y,N):
Mt=['*']*N
for i in range(N+1,len(y)+2):
M=y[i-(N+1):i-1].mean()
Mt.append(round(M))
return Mt
yt3=MoveAverage(y,3)
s3=np.sqrt(((y[3:]-yt3[3:-1])**2).mean())
yt5=MoveAverage(y,5)
s5=np.sqrt(((y[5:]-yt5[5:-1])**2).mean())
print('N=3时,预测值:',yt3,',预测的标准误差:',s3)
print('N=5时,预测值:',yt5,',预测的标准误差:',s5)
简单移动平均使用的是等量加权策略,可以利用卷积,相应代码如下:
def sma(arr,n):
weights=np.ones(n)/n
return np.convolve(weights,arr)[n-1:-n+1]
另一种写法
import numpy as np
y=np.array([423,358,434,445,527,429,426,502,480,384,427,446])
n1=3; yt1=np.convolve(np.ones(n1)/n1,y)[n1-1:-n1+1]
s1=np.sqrt(((y[n1:]-yt1[:-1])**2).mean())
n2=5; yt2=np.convolve(np.ones(n2)/n2,y)[n2-1:-n2+1]
s2=np.sqrt(((y[n2:]-yt2[:-1])**2).mean())
print('N=3时,预测值:',yt1,',预测的标准误差:',s1)
print('N=5时,预测值:',yt2,',预测的标准误差:',s2)
当预测目标的基本趋势是在某一水平上下波动时, 可用一次移动平均 方法建立预测模型。当预测目标的基本䞟势与某一线性模型相吻合时, 常用二次移动平均法。但序列同时存在线性趋势与周期波动时, 可用趋势移动平 均法建立预测模型 $$ \hat{\boldsymbol{y}}_{T+m}=a_{T}+b_{T} m, \quad m=1,2, \cdots, $$ 其中 $a_{T}=2 M_{T}^{(1)}-M_{T}^{(2)}, b_{T}=\frac{2}{N-1}\left(M_{T}^{(1)}-M_{T}^{(2)}\right)$ 。
import numpy as np
y=np.array([423,358,434,445,527,429,426,502,480,384,427,446])
def MoveAverage(y,N):
Mt=['*']*N
for i in range(N+1,len(y)+2):
M=y[i-(N+1):i-1].mean()
Mt.append(round(M))
return Mt
yt3=MoveAverage(y,3)
s3=np.sqrt(((y[3:]-yt3[3:-1])**2).mean())
yt5=MoveAverage(y,5)
s5=np.sqrt(((y[5:]-yt5[5:-1])**2).mean())
print('N=3时,预测值:',yt3,',预测的标准误差:',s3)
print('N=5时,预测值:',yt5,',预测的标准误差:',s5)
N=3时,预测值: ['*', '*', '*', 405, 412, 469, 467, 461, 452, 469, 455, 430, 419] ,预测的标准误差: 56.60388679233962 N=5时,预测值: ['*', '*', '*', '*', '*', 437, 439, 452, 466, 473, 444, 444, 448] ,预测的标准误差: 39.89808445097513
def sma(arr,n):
weights=np.ones(n)/n
return np.convolve(weights,arr)[n-1:-n+1]
import numpy as np
y=np.array([423,358,434,445,527,429,426,502,480,384,427,446])
n1=3; yt1=np.convolve(np.ones(n1)/n1,y)[n1-1:-n1+1]
s1=np.sqrt(((y[n1:]-yt1[:-1])**2).mean())
n2=5; yt2=np.convolve(np.ones(n2)/n2,y)[n2-1:-n2+1]
s2=np.sqrt(((y[n2:]-yt2[:-1])**2).mean())
print('N=3时,预测值:',yt1,',预测的标准误差:',s1)
print('N=5时,预测值:',yt2,',预测的标准误差:',s2)
N=3时,预测值: [405. 412.33333333 468.66666667 467. 460.66666667 452.33333333 469.33333333 455.33333333 430.33333333 419. ] ,预测的标准误差: 56.57519850976887 N=5时,预测值: [437.4 438.6 452.2 465.8 472.8 444.2 443.8 447.8] ,预测的标准误差: 39.81586187868923